#include <vector>
#include <string>
#include <iostream>
#include <cstdlib>

#include "mem.h"
#include "error.h"

using namespace std;

static vector <var> symTable;
void listVars();

void listVars()
{
    /* List the variables that currently reside in the symbol table; for debugging purposes only */
    if(symTable.empty())
        cerr<<"No variables are in memory!"<<endl;
    else
        for(unsigned int i=0; i<symTable.size(); i++)
            clog<<symTable.at(i).varName<<" "<<(int)symTable.at(i).varType<<" str="<< \
            symTable.at(i).strData<<" bool="<<symTable.at(i).boolData<<" num="<< \
            symTable.at(i).numData<<endl;
}

bool addVar(const string& _varName, uint8_t _varType, bool _isInit, const string& _strData, \
            double _numData, bool _boolData)
{
    /* Adds a variable to the symbol table if it does not exist already */
    var _var;
    if(isVarExist(_varName) == NOT_FOUND)
    {
        _var.boolData = _boolData;
        _var.varName = _varName;
        _var.numData = _numData;
        _var.strData = _strData;
        _var.varType = _varType;
        _var.isInit = _isInit;

        symTable.push_back(_var);
        return true;
    }
    else
        return false;
}

int isVarExist(const std::string& _varName)
{
    /* Checks if a variable already exists in the symbol table */
    for(unsigned int i=0; i<symTable.size(); i++)
        if(_varName == symTable.at(i).varName)
            return i;

    return NOT_FOUND;
}

bool removeVar(const string& _varName)
{
    /* Removes an existing variable from the symbol table */
    int i;
    if((i = isVarExist(_varName)) != NOT_FOUND)
    {
        symTable.erase(symTable.begin() + i);
        return true;
    }
    else
        return false;
}

uint8_t getVarType(const string& _varName)
{
    int varIdx = isVarExist(_varName);

    if(varIdx != NOT_FOUND)
        return symTable.at(varIdx).varType;
    else
        return NOT_FOUND;
}

string getStrData(const string& _varName, int nLine)
{
    int varIdx = isVarExist(_varName);

    if(varIdx != NOT_FOUND && getVarType(_varName) == VAR_STRING)
        return symTable.at(varIdx).strData;
    else
        errorMessage(ERR_IDENT_MISMATCH, "foo", nLine);

    return "foo";   /* To stop warnings about control reaching end of non-void function */
}

bool getBoolData(const string& _varName, int nLine)
{
    int varIdx = isVarExist(_varName);

    if(varIdx != NOT_FOUND && getVarType(_varName) == VAR_BOOL)
        return symTable.at(varIdx).boolData;
    else
        errorMessage(ERR_IDENT_MISMATCH, "foo", nLine);

    return true;    /* To stop warnings about control reaching end of non-void function */
}

double getNumData(const string& _varName, int nLine)
{
    int varIdx = isVarExist(_varName);

    if(varIdx != NOT_FOUND && getVarType(_varName) == VAR_NUM)
        return symTable.at(varIdx).numData;
    else
        errorMessage(ERR_IDENT_MISMATCH, "foo", nLine);

    return 0.0; /* To stop warnings about control reaching end of non-void function */
}

bool isVarInit(const string& _varName, int nLine)
{
    int varIdx = isVarExist(_varName);

    if(varIdx != NOT_FOUND && symTable.at(varIdx).isInit)
        return true;

    else if(varIdx != NOT_FOUND && !symTable.at(varIdx).isInit)
        return false;

    else if(varIdx == NOT_FOUND)
        errorMessage(ERR_INVALID_IDENT, _varName, nLine);

    return true;    /* To stop warnings about control reaching end of non-void function */
}
